﻿#include "ImageRotate.h"
#include <QDebug>
using namespace cv;

cv::Mat imageRotateFixSize(const cv::Mat &src, double degree) noexcept
{
    if(src.empty()) return cv::Mat();
    Mat newImg;
    cv::Point2f pt = cv::Point2f(src.cols / 2.0f, src.rows / 2.0f);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);
    cv::warpAffine(src, newImg, M, src.size());
    return newImg;
}

cv::Mat imageRotateFixSize(const cv::Mat &src, double degree, cv::Point2f center) noexcept
{
    if(src.empty()) return cv::Mat();
    cv::Mat dst;
    cv::Mat affine_matrix = cv::getRotationMatrix2D( center, degree, 1.0 );
    cv::warpAffine(src, dst, affine_matrix, src.size());
    return dst;
}

bool imageRotateFixSize(const cv::Mat &src, double degree, cv::Mat &dst) noexcept
{
    if(src.empty()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    cv::Point2f pt = cv::Point2f(x, y);
    cv::Mat matrix = cv::getRotationMatrix2D(pt, degree, 1.0);

    cv::warpAffine(src, dst, matrix, src.size());
    return true;
}

bool imageRotateFixSize(const cv::Mat &src, double degree, cv::Point2f center, cv::Mat &dst) noexcept
{
    if(src.empty()) return false;
    cv::Mat affine_matrix = cv::getRotationMatrix2D( center, degree, 1.0 );
    cv::warpAffine(src, dst, affine_matrix, src.size());
    return true;
}

bool imageRotateFixSize(const cv::Mat &src, const cv::Mat &mask, double degree, cv::Mat &dst, cv::Mat &mask_out) noexcept
{
    if(src.empty()) return false;
    if(src.size() != mask.size()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    cv::Point2f pt = cv::Point2f(x, y);
    Mat matrix = cv::getRotationMatrix2D(pt, degree, 1.0);

    cv::warpAffine(src, dst, matrix, src.size());
    cv::warpAffine(mask, mask_out, matrix, src.size());
    return true;
}

bool imageRotateFixSize(const cv::Mat &src, double degree, cv::Mat &dst, cv::Mat &mask) noexcept
{
    if(src.empty()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    cv::Point2f pt = cv::Point2f(x, y);
    Mat matrix = cv::getRotationMatrix2D(pt, degree, 1.0);

    cv::warpAffine(src, dst, matrix, src.size());

    cv::Mat m = cv::Mat(src.rows, src.cols, CV_8U, 255);
    cv::warpAffine(m, mask, matrix, src.size());
    return true;
}

cv::Mat imageRotateAutoSize(const cv::Mat &src, double degree) noexcept
{
    double x = (double)src.cols / 2.0f;
    double y = (double)src.rows / 2.0f;

    double rad = degree / 180.0 * 3.1415926535;

    double c = cos(rad), s = sin(rad);
    double nx1 = fabs(c * x + s * y);
    double ny1 = fabs(-s * x + c * y);
    double nx2 = fabs(c * x - s * y);
    double ny2 = fabs(-s * x - c * y);

    int nw = static_cast<int>(2.0f * std::max(nx1, nx2) + 0.5);
    int nh = static_cast<int>(2.0f * std::max(ny1, ny2) + 0.5);

    Mat newImage;

    cv::Point2f pt = cv::Point2f(x, y);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);

    M.at<double>(0, 2) += nw / 2.0 - x;
    M.at<double>(1, 2) += nh / 2.0 - y;

    cv::warpAffine(src, newImage, M, Size(nw, nh));
    return newImage;
}

bool imageRotateAutoSize(const cv::Mat &src, double degree, cv::Mat &dst)
{
    if(src.empty()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    double rad = degree / 180.0 * 3.1415926535;

    double c = cos(rad), s = sin(rad);
    double nx1 = fabs(c * x + s * y);
    double ny1 = fabs(-s * x + c * y);
    double nx2 = fabs(c * x - s * y);
    double ny2 = fabs(-s * x - c * y);

    int nw = static_cast<int>(2.0f * std::max(nx1, nx2) + 0.5); // +0.5 是四舍五入
    int nh = static_cast<int>(2.0f * std::max(ny1, ny2) + 0.5);

    cv::Point2f pt = cv::Point2f(x, y);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);

    M.at<double>(0, 2) += nw / 2.0 - x;
    M.at<double>(1, 2) += nh / 2.0 - y;

    cv::warpAffine(src, dst, M, Size(nw, nh));
    return true;
}

bool imageRotateAutoSize(const cv::Mat &src, double degree, cv::Mat &dst, cv::Mat &mask)
{
    if(src.empty()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    double rad = degree / 180.0 * 3.1415926535;

    double c = cos(rad), s = sin(rad);
    double nx1 = fabs(c * x + s * y);
    double ny1 = fabs(-s * x + c * y);
    double nx2 = fabs(c * x - s * y);
    double ny2 = fabs(-s * x - c * y);

    int nw = static_cast<int>(2.0f * std::max(nx1, nx2) + 0.5); // +0.5 是四舍五入
    int nh = static_cast<int>(2.0f * std::max(ny1, ny2) + 0.5);

    cv::Point2f pt = cv::Point2f(x, y);
    Mat matrix = cv::getRotationMatrix2D(pt, degree, 1.0);

    matrix.at<double>(0, 2) += nw / 2.0 - x;
    matrix.at<double>(1, 2) += nh / 2.0 - y;

    cv::warpAffine(src, dst, matrix, Size(nw, nh));

    cv::Mat m = cv::Mat(src.rows, src.cols, CV_8U, 255);
    cv::warpAffine(m, mask, matrix, Size(nw, nh));
    return true;
}

bool imageRotateAutoSize(const cv::Mat &src, const cv::Mat &mask, double degree, cv::Mat &dst, cv::Mat &mask_out) noexcept
{
    if(src.empty()) return false;
    if(src.size() != mask.size()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    double rad = degree / 180.0 * 3.1415926535;

    double c = cos(rad), s = sin(rad);
    double nx1 = fabs(c * x + s * y);
    double ny1 = fabs(-s * x + c * y);
    double nx2 = fabs(c * x - s * y);
    double ny2 = fabs(-s * x - c * y);

    int nw = static_cast<int>(2.0f * std::max(nx1, nx2) + 0.5); // +0.5 是四舍五入
    int nh = static_cast<int>(2.0f * std::max(ny1, ny2) + 0.5);

    cv::Point2f pt = cv::Point2f(x, y);
    Mat matrix = cv::getRotationMatrix2D(pt, degree, 1.0);

    matrix.at<double>(0, 2) += nw / 2.0 - x;
    matrix.at<double>(1, 2) += nh / 2.0 - y;

    cv::warpAffine(src, dst, matrix, Size(nw, nh));
    cv::warpAffine(mask, mask_out, matrix, Size(nw, nh));
    return true;
}

Mat imageRotateFullSize(const cv::Mat &src, double degree) noexcept
{
    if(src.empty()) return cv::Mat();
    double x = src.cols / 2.0; // 中心点坐标
    double y = src.rows / 2.0;

    int diagonal = static_cast<int> (hypot(src.cols, src.rows) + 0.5);    // 计算对角线长度, +0.5 是四舍五入
    Mat newImage;

    cv::Point2f pt = cv::Point2f(x, y);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);

    M.at<double>(0, 2) += diagonal / 2.0 - x;
    M.at<double>(1, 2) += diagonal / 2.0 - y;

    cv::warpAffine(src, newImage, M, Size(diagonal, diagonal));
    return newImage;
}

bool imageRotateFullSize(const cv::Mat &src, double degree, cv::Mat &dst)
{
    if(src.empty()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    int diagonal = static_cast<int> (hypot(src.cols, src.rows) + 0.5);    // 计算对角线长度, +0.5 是四舍五入

    cv::Point2f pt = cv::Point2f(x, y);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);

    M.at<double>(0, 2) += diagonal / 2.0 - x;
    M.at<double>(1, 2) += diagonal / 2.0 - y;

    cv::warpAffine(src, dst, M, Size(diagonal, diagonal));
    return true;
}

bool imageRotateFullSize(const cv::Mat &src, double degree, cv::Mat &dst, cv::Mat &mask)
{
    if(src.empty()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    int diagonal = static_cast<int> (hypot(src.cols, src.rows) + 0.5);    // 计算对角线长度, +0.5 是四舍五入

    cv::Point2f pt = cv::Point2f(x, y);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);

    M.at<double>(0, 2) += diagonal / 2.0 - x;
    M.at<double>(1, 2) += diagonal / 2.0 - y;

    cv::warpAffine(src, dst, M, Size(diagonal, diagonal));

    cv::Mat m = cv::Mat(src.rows, src.cols, CV_8U, 255);
    cv::warpAffine(m, mask, M, Size(diagonal, diagonal));
    return true;
}

bool imageRotateFullSize(const cv::Mat &src, const cv::Mat &mask, double degree, cv::Mat &dst, cv::Mat &mask_out) noexcept
{
    if(src.empty()) return false;
    if(src.size() != mask.size()) return false;
    double x = src.cols / 2.0;
    double y = src.rows / 2.0;

    int diagonal = static_cast<int> (hypot(src.cols, src.rows) + 0.5);    // 计算对角线长度, +0.5 是四舍五入

    cv::Point2f pt = cv::Point2f(x, y);
    Mat M = cv::getRotationMatrix2D(pt, degree, 1.0);

    M.at<double>(0, 2) += diagonal / 2.0 - x;
    M.at<double>(1, 2) += diagonal / 2.0 - y;


    cv::warpAffine(src, dst, M, Size(diagonal, diagonal));
    cv::warpAffine(mask, mask_out, M, Size(diagonal, diagonal));
    return true;
}

